Let’s check out the data!

library(readr)
amazon <- read_csv("amazon_jobs_dataset.csv")
Missing column names filled in: 'X1' [1]Parsed with column specification:
cols(
  X1 = col_integer(),
  Title = col_character(),
  location = col_character(),
  Posting_date = col_character(),
  DESCRIPTION = col_character(),
  `BASIC QUALIFICATIONS` = col_character(),
  `PREFERRED QUALIFICATIONS` = col_character()
)
head(amazon)

Questions that we can focus on: - What are the popular locations of job openings? - Are there certain months when job opening are more? - How many jobs are posted every year? - How many jobs are posted every month? - What are most popular job titles? - What are minimum educational qualifications? - Which job requires higher degree? - What languages are required for jobs? - How many years of experience is required? - Which job categories require more experience? - Word clouds of preferred qualifications - Word clouds of Basic Qualifications - Word clouds of JOb description

dim(amazon)
[1] 3493    7
unique(amazon$Posting_date)[1:20]
 [1] "March  1, 2018"    "February 28, 2018" "February 27, 2018" "February 26, 2018" "February 25, 2018"
 [6] "February 24, 2018" "February 23, 2018" "February 22, 2018" "February 21, 2018" "February 20, 2018"
[11] "February 19, 2018" "February 18, 2018" "February 16, 2018" "February 15, 2018" "February 14, 2018"
[16] "February 13, 2018" "February 12, 2018" "February 11, 2018" "February  9, 2018" "February  8, 2018"

We see that in some dates, there are multiple spaces between month and day. Let’s split it to year month and day.

library(stringr)
amazon$posting_month <- str_extract(amazon$Posting_date , "([A-Za-z]+)")
amazon$posting_day <- str_extract(amazon$Posting_date , "([0-9]+)")
amazon$posting_year <- str_extract(amazon$Posting_date, "([0-9]{4})")
unique(amazon$posting_month)
 [1] "March"     "February"  "January"   "December"  "November"  "October"   "September" "August"    "July"     
[10] "June"      "May"       "April"    
unique(amazon$posting_day)
 [1] "1"  "28" "27" "26" "25" "24" "23" "22" "21" "20" "19" "18" "16" "15" "14" "13" "12" "11" "9"  "8"  "7"  "6" 
[23] "5"  "4"  "3"  "2"  "31" "30" "29" "17" "10"
unique(amazon$posting_year)
[1] "2018" "2017" "2016" "2015" "2014" "2013" "2012" "2011"

Let’s also extract the countries from location column.

amazon$country <- str_extract(amazon$location, "[A-Za-z]+")
unique(amazon$country)
 [1] "US" "IN" "RO" "CA" "DE" "PL" "AE" "ES" "IT" "IL" "UK" "ZA" "SG" "AU" "IE" "FR" "BR" "CN" "MX" "NL" "JO" "TW"
[23] "LU" "JP" NA  
unique(amazon$location)
 [1] "US, WA, Seattle"           "IN, KA, Bangalore"         "US, CA, Cupertino"         "RO, Ia<U+015F>i"          
 [5] "US, CA, East Palo Alto"    "US, CA, Santa Monica"      "US, CA, Sunnyvale"         "US, CA, Palo Alto"        
 [9] "US, MA, Boston"            "US, MA, Cambridge"         "CA, BC, Vancouver"         "US, TX, Austin"           
[13] "IN, TS, Hyderabad"         "US, CA, San Francisco"     "DE, BY, Munich"            "RO, Iasi"                 
[17] "PL, Gdansk"                "PL, Bielany Wroclawskie"   "DE, Berlin"                "US, CA, Irvine"           
[21] "CA, ON, Toronto"           "US, MA, North Reading"     "US, MN, Minneapolis"       "AE, Dubai"                
[25] "US, CA, San Diego"         "US, CA, Santa Barbara"     "US, OR, Portland"          "ES, Madrid"               
[29] "IT, Vercelli"              "US, NJ, Newark"            "US, NY, New York"          "IN, TN, Chennai"          
[33] "IL, Herzliya"              "DE, Aachen"                "US, MA, Westborough"       "US, VA, Herndon"          
[37] "US, WA, Bellevue"          "UK, London"                "ZA, Cape Town"             "US, MA, Andover"          
[41] "US, CO, Boulder"           "US, CA, Santa Cruz"        "US, CA, San Luis Obispo"   "UK, Cambridge"            
[45] "SG, Singapore"             "AU, NSW, Sydney"           "IE, DUBLIN, Dublin"        "US, CO, Broomfield"       
[49] "FR, Paris"                 "US, Virtual"               "UK, Edinburgh"             "US, AZ, Tempe"            
[53] "IL, Haifa"                 "BR, SP, Sao Paulo"         "IN, DL, Gurgaon"           "IN, HR, Gurgaon"          
[57] "CN, Beijing"               "MX, EMEX, Mexico City"     "NL, The Hague"             "US, VA, Ballston"         
[61] "IT, MI, Milan"             "JO, Amman"                 "CA, MB, Winnipeg"          "US, PA, Pittsburgh"       
[65] "CN, Shenzhen"              "US, GA, Atlanta"           "UK, N YORK, Heslington"    "US, NJ, Jersey City"      
[69] "TW, TP, Taipei"            "US, CO, Denver"            "DE, BY, Graben"            "CN, Shanghai"             
[73] "RO, Bucharest"             "DE, SN, Dresden"           "LU, Luxembourg"            "DE, Standortuebergreifend"
[77] "US, CA, Foster City"       "UK, CAMBS, Cambridge"      "IL, Hod Hasharon"          "JP, Meguro"               
[81] "IT, AT, Asti"              "IL,"                       "UK, BRIST, Bristol"        "CA, ON,"                  
[85] "IN, MH, Pune"              "US, CA, San Jose"          "CA,"                       "CA, ON, Ottawa"           
[89] NA                          "US, NV, Las Vegas"        
amazon$city <- word(amazon$location, -1)
unique(amazon$city)
 [1] "Seattle"               "Bangalore"             "Cupertino"             "Ia<U+015F>i"          
 [5] "Alto"                  "Monica"                "Sunnyvale"             "Boston"               
 [9] "Cambridge"             "Vancouver"             "Austin"                "Hyderabad"            
[13] "Francisco"             "Munich"                "Iasi"                  "Gdansk"               
[17] "Wroclawskie"           "Berlin"                "Irvine"                "Toronto"              
[21] "Reading"               "Minneapolis"           "Dubai"                 "Diego"                
[25] "Barbara"               "Portland"              "Madrid"                "Vercelli"             
[29] "Newark"                "York"                  "Chennai"               "Herzliya"             
[33] "Aachen"                "Westborough"           "Herndon"               "Bellevue"             
[37] "London"                "Town"                  "Andover"               "Boulder"              
[41] "Cruz"                  "Obispo"                "Singapore"             "Sydney"               
[45] "Dublin"                "Broomfield"            "Paris"                 "Virtual"              
[49] "Edinburgh"             "Tempe"                 "Haifa"                 "Paulo"                
[53] "Gurgaon"               "Beijing"               "City"                  "Hague"                
[57] "Ballston"              "Milan"                 "Amman"                 "Winnipeg"             
[61] "Pittsburgh"            "Shenzhen"              "Atlanta"               "Heslington"           
[65] "Taipei"                "Denver"                "Graben"                "Shanghai"             
[69] "Bucharest"             "Dresden"               "Luxembourg"            "Standortuebergreifend"
[73] "Hasharon"              "Meguro"                "Asti"                  "IL,"                  
[77] "Bristol"               "ON,"                   "Pune"                  "Jose"                 
[81] "CA,"                   "Ottawa"                NA                      "Vegas"                

Let us correct the city names that have multiple words.

amazon$city <- gsub(pattern = "Alto", replacement = "East Palo Alto", amazon$city)
amazon$city <- gsub(pattern = "Ia<U+015F>i", replacement = "Iasi", amazon$city)
amazon$city <- gsub(pattern = "Monica", replacement = "Santa Monica", amazon$city)
amazon$city <- gsub(pattern = "Francisco", replacement = "San Francisco", amazon$city)
amazon$city <- gsub(pattern = "Wroclawskie", replacement = "Bielany Wroclawskie", amazon$city)
amazon$city <- gsub(pattern = "Diego", replacement = "San Diego", amazon$city)
amazon$city <- gsub(pattern = "Barbara", replacement = "Santa Barbara", amazon$city)
amazon$city <- gsub(pattern = "York", replacement = "New York", amazon$city)
amazon$city <- gsub(pattern = "Town", replacement = "Cape Town", amazon$city)
amazon$city <- gsub(pattern = "Cruz", replacement = "Santa Cruz", amazon$city)
amazon$city <- gsub(pattern = "Obispo", replacement = "San Luis Obispo", amazon$city)
amazon$city <- gsub(pattern = "Paulo", replacement = "Sao Paulo", amazon$city)
amazon$city <- gsub(pattern = "Hasharon", replacement = "Hod Hasharon", amazon$city)
amazon$city <- gsub(pattern = "IL,", replacement = "Hod Hasharon", amazon$city)
amazon$city <- gsub(pattern = "On,", replacement = "Ottawa", amazon$city)
amazon$city <- gsub(pattern = "Jose", replacement = "San Jose", amazon$city)
amazon$city <- gsub(pattern = "CA,", replacement = "Ottawa", amazon$city)
amazon$city <- gsub(pattern = "Vegas", replacement = "Las Vegas", amazon$city)

The word “City” has been used with three different cities, so include them.

amazon$city <- ifelse(amazon$location == "US, CA, Foster City", "Foster City", amazon$city)
amazon$city <- ifelse(amazon$location == "MX, EMEX, Mexico City", "Mexico City", amazon$city)
amazon$city <- ifelse(amazon$location == "US, NJ, Jersey City", "Jersey City", amazon$city)
head(amazon)

Analysis of Job Posting Date

How many jobs are posted every year and every month? Is there a certain period of year when jobs are posted more fequently?

amazon$Posting_date <- paste(amazon$posting_year, amazon$posting_month, amazon$posting_day,sep="-")
amazon$Posting_date <- as.Date(strptime(amazon$Posting_date,format="%Y-%b-%d"))
#amazon$Posting_date$zone <- NULL
(amazon$Posting_date[1:10])
 [1] "2018-03-01" "2018-03-01" "2018-03-01" "2018-03-01" "2018-03-01" "2018-03-01" "2018-03-01" "2018-03-01"
 [9] "2018-03-01" "2018-03-01"
#get day of the week based on date
dow <- function(x) format(as.Date(x), "%A")
amazon$weekday <- dow(amazon$Posting_date)
amazon$weekday[1:20]
 [1] "Thursday"  "Thursday"  "Thursday"  "Thursday"  "Thursday"  "Thursday"  "Thursday"  "Thursday"  "Thursday" 
[10] "Thursday"  "Thursday"  "Thursday"  "Thursday"  "Wednesday" "Wednesday" "Wednesday" "Wednesday" "Wednesday"
[19] "Wednesday" "Wednesday"
posting_date <- amazon[,c("posting_month", "posting_year", "weekday", "Posting_date")]
head(posting_date)
year <- as.data.frame(table(posting_date$posting_year))
colnames(year) <- c("Year", "Freq")
p5 <- ggplot(data = year, aes(Year, Freq, fill = Year)) +
      geom_bar(stat = "identity") +
      geom_text(aes(label=Freq), color="black", size=3) +
      ggtitle("Jobs postings by Year") + 
      guides(fill=FALSE) +
      tilt_theme 
p5

mon <- as.data.frame(table(posting_date$posting_month))
colnames(mon) <- c("Mon", "Freq")
lev = c("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December")
mon$Month <- factor(mon$Mon, lev)
 
p6 <- ggplot(data = mon, aes(Month, Freq, fill = Month)) +
      geom_bar(stat = "identity") +
      geom_text(aes(label=Freq), color="black", size=3) +
      ggtitle("Jobs postings by Month") + 
      guides(fill=FALSE) +
      tilt_theme 
p6

jday <- as.data.frame(table(posting_date$weekday))
colnames(jday) <- c("wd", "Freq")
lev <- c("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
jday$weekday <- factor(jday$wd, lev)
p7 <- ggplot(data = jday, aes(weekday, Freq, fill = weekday)) +
      geom_bar(stat = "identity") +
      geom_text(aes(label=Freq), color="black", size=3) +
      ggtitle("Jobs postings by Weekday") + 
      guides(fill=FALSE) +
      tilt_theme 
p7

The above graphs show that most of the job postings are recent and there has been large increase in jobs in 2017 and 2018. January and february are hot months for jobs. Also, the jobs are posted generally on weekdays, mostly on tuesdays and wednesday. This is true as generally employees are completing more work in the first half of weekdays.

Analysis of Job titles

What are minimum educational qualifications?

amazon$education <- NA
degree_list = c("ba", "bs", "b.tech","bachelor", "phd","ms","master", "mba","m.tech")
amazon$`BASIC QUALIFICATIONS` <- tolower(amazon$`BASIC QUALIFICATIONS`)
for(i in degree_list){
  amazon$deg1 <- grepl(i, amazon$`BASIC QUALIFICATIONS`)
  amazon$education <- ifelse(amazon$deg1 == "TRUE", i, amazon$education)
}
amazon$education <- ifelse(is.na(amazon$education), "other", amazon$education)
amazon <- subset(amazon, select = -c(deg1))
edu <- as.data.frame(table(amazon$education))
colnames(edu) <- c("Education", "Freq")
p10 <- ggplot(data = edu, aes(Education, Freq, fill = Education)) +
      geom_bar(stat = "identity") +
      geom_text(aes(label=Freq), color="black", size=3) +
      ggtitle("Jobs based on degrees") + 
      guides(fill=FALSE) +
      coord_flip() 
p10

Basic Qualifications generally requires Masters degree.

Which jobs require which type of degrees?

What languages are in demand?

list_of_occurence <- c()
languages <- c('swift','matlab','mongodb','hadoop','cosmos', 'mysql','spark', 'pig', 'python', 'java.', 'java,','c[++]', 'php', 'javascript', 'objective c', 'ruby', 'perl','c ','c#', ' r,')
amazon$`PREFERRED QUALIFICATIONS` <- tolower(amazon$`PREFERRED QUALIFICATIONS`)
for(i in languages){
  amazon$dummy <- str_count(amazon$`PREFERRED QUALIFICATIONS`, i)
  list_of_occurence <- c(list_of_occurence, sum(amazon$dummy, na.rm = TRUE))
}
list_of_occurence
 [1]   26    9   16  164    1   50  128   20  378 1080  392  504   34  348   79  237  188  630  139    7
lan <- data.frame(cbind(languages, as.numeric(list_of_occurence)))
p15 <- ggplot(data = lan, aes(languages, list_of_occurence, fill = languages)) +
      geom_bar(stat = "identity") +
      geom_text(aes(label=list_of_occurence), color="black", size=3) +
      ggtitle("Languages in job description") + 
      guides(fill=FALSE) +
      coord_flip() 
p15

Java, C, C++ and python are popular on-demand languages in jobs.

How many years of experience is required?

amazon$dummy <- str_extract(amazon$`BASIC QUALIFICATIONS`, '([0-9]+) year')
amazon$dummy <- ifelse(is.na(amazon$dummy), "0 year", amazon$dummy)
split_year <- function(var){
 return(as.numeric(unlist(str_split(var, " "))[1]))
}
amazon$experience <- sapply(amazon$dummy, split_year)

Let’s see the experience, excluding 0 year experience.

exp <- as.data.frame(table(amazon$experience))
colnames(exp) <- c("Experience", "Freq")
p16 <- ggplot(data = filter(exp, exp$Experience != 0), aes(Experience, Freq, fill = Experience)) +
      geom_bar(stat = "identity") +
      geom_text(aes(label=Freq), color="black", size=3) +
      ggtitle("Experience needed") + 
      guides(fill=FALSE) +
      coord_flip() 
p16

Word Clouds of Qualifications and Job description

library(wordcloud)
library(SnowballC)
library(RColorBrewer)
library(tm)
texts <- amazon$`PREFERRED QUALIFICATIONS`
#texts <- iconv(texts, to = "utf-8")
corpus <- Corpus(VectorSource(texts))
corpus <- tm_map(corpus, PlainTextDocument)
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeWords, stopwords('english'))
#corpus <- tm_map(corpus, stemDocument)
corpus <- tm_map(corpus, removeWords, c("00b7","and", "this", "there")) 
corpus <- Corpus(VectorSource(corpus))
dtm <- TermDocumentMatrix(corpus)
m <- as.matrix(dtm)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
head(d, 10)
d <- d[-which(d$word %in% c("00b7","and","this","that")),]
set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 1,
          max.words=200, random.order=FALSE, rot.per=0.35, 
          colors=brewer.pal(8, "Dark2"))
title("Preferred Qualifications Word Cloud")

texts <- amazon$`BASIC QUALIFICATIONS`
#texts <- iconv(texts, to = "utf-8")
corpus <- Corpus(VectorSource(texts))
corpus <- tm_map(corpus, PlainTextDocument)
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeWords, stopwords('english'))
#corpus <- tm_map(corpus, stemDocument)
corpus <- tm_map(corpus, removeWords, c("00b7","and", "this", "there")) 
corpus <- Corpus(VectorSource(corpus))
dtm <- TermDocumentMatrix(corpus)
m <- as.matrix(dtm)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
head(d, 10)
d <- d[-which(d$word %in% c("00b7","and","this","that")),]
set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 1,
          max.words=200, random.order=FALSE, rot.per=0.35, 
          colors=brewer.pal(8, "Dark2"))
title("Basic Qualifications Word Cloud")

texts <- amazon$Title
#texts <- iconv(texts, to = "utf-8")
corpus <- Corpus(VectorSource(texts))
corpus <- tm_map(corpus, PlainTextDocument)
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeWords, stopwords('english'))
#corpus <- tm_map(corpus, stemDocument)
corpus <- tm_map(corpus, removeWords, c("00b7","and", "this", "there", "you", "will")) 
corpus <- Corpus(VectorSource(corpus))
dtm <- TermDocumentMatrix(corpus)
m <- as.matrix(dtm)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
head(d, 10)
#d <- d[-which(d$word %in% c("00b7","and","this","that", "you", "will")),]
set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 1,
          max.words=200, random.order=FALSE, rot.per=0.35, 
          colors=brewer.pal(8, "Dark2"))
title("Job Title Word Cloud")

LS0tCnRpdGxlOiAiQW1hem9uIEpvYnMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkxldCdzIGNoZWNrIG91dCB0aGUgZGF0YSEKCmBgYHtyfQpsaWJyYXJ5KHJlYWRyKQphbWF6b24gPC0gcmVhZF9jc3YoImFtYXpvbl9qb2JzX2RhdGFzZXQuY3N2IikKaGVhZChhbWF6b24pCmBgYAoKUXVlc3Rpb25zIHRoYXQgd2UgY2FuIGZvY3VzIG9uOgogIC0gV2hhdCBhcmUgdGhlIHBvcHVsYXIgbG9jYXRpb25zIG9mIGpvYiBvcGVuaW5ncz8KICAtIEFyZSB0aGVyZSBjZXJ0YWluIG1vbnRocyB3aGVuIGpvYiBvcGVuaW5nIGFyZSBtb3JlPyAKICAgIC0gSG93IG1hbnkgam9icyBhcmUgcG9zdGVkIGV2ZXJ5IHllYXI/CiAgICAtIEhvdyBtYW55IGpvYnMgYXJlIHBvc3RlZCBldmVyeSBtb250aD8KICAtIFdoYXQgYXJlIG1vc3QgcG9wdWxhciBqb2IgdGl0bGVzPwogIC0gV2hhdCBhcmUgbWluaW11bSBlZHVjYXRpb25hbCBxdWFsaWZpY2F0aW9ucz8KICAgIC0gV2hpY2ggam9iIHJlcXVpcmVzIGhpZ2hlciBkZWdyZWU/CiAgLSBXaGF0IGxhbmd1YWdlcyBhcmUgcmVxdWlyZWQgZm9yIGpvYnM/CiAgLSBIb3cgbWFueSB5ZWFycyBvZiBleHBlcmllbmNlIGlzIHJlcXVpcmVkPwogICAgLSBXaGljaCBqb2IgY2F0ZWdvcmllcyByZXF1aXJlIG1vcmUgZXhwZXJpZW5jZT8KICAtIFdvcmQgY2xvdWRzIG9mIHByZWZlcnJlZCBxdWFsaWZpY2F0aW9ucwogIC0gV29yZCBjbG91ZHMgb2YgQmFzaWMgUXVhbGlmaWNhdGlvbnMKICAtIFdvcmQgY2xvdWRzIG9mIEpPYiBkZXNjcmlwdGlvbgoKYGBge3J9CmRpbShhbWF6b24pCmBgYApgYGB7cn0KdW5pcXVlKGFtYXpvbiRQb3N0aW5nX2RhdGUpWzE6MjBdCmBgYAoKV2Ugc2VlIHRoYXQgaW4gc29tZSBkYXRlcywgdGhlcmUgYXJlIG11bHRpcGxlIHNwYWNlcyBiZXR3ZWVuIG1vbnRoIGFuZCBkYXkuIExldCdzIHNwbGl0IGl0IHRvIHllYXIgbW9udGggYW5kIGRheS4KCmBgYHtyfQpsaWJyYXJ5KHN0cmluZ3IpCmFtYXpvbiRwb3N0aW5nX21vbnRoIDwtIHN0cl9leHRyYWN0KGFtYXpvbiRQb3N0aW5nX2RhdGUgLCAiKFtBLVphLXpdKykiKQphbWF6b24kcG9zdGluZ19kYXkgPC0gc3RyX2V4dHJhY3QoYW1hem9uJFBvc3RpbmdfZGF0ZSAsICIoWzAtOV0rKSIpCmFtYXpvbiRwb3N0aW5nX3llYXIgPC0gc3RyX2V4dHJhY3QoYW1hem9uJFBvc3RpbmdfZGF0ZSwgIihbMC05XXs0fSkiKQpgYGAKCmBgYHtyfQp1bmlxdWUoYW1hem9uJHBvc3RpbmdfbW9udGgpCnVuaXF1ZShhbWF6b24kcG9zdGluZ19kYXkpCnVuaXF1ZShhbWF6b24kcG9zdGluZ195ZWFyKQpgYGAKTGV0J3MgYWxzbyBleHRyYWN0IHRoZSBjb3VudHJpZXMgZnJvbSBsb2NhdGlvbiBjb2x1bW4uCgpgYGB7cn0KYW1hem9uJGNvdW50cnkgPC0gc3RyX2V4dHJhY3QoYW1hem9uJGxvY2F0aW9uLCAiW0EtWmEtel0rIikKdW5pcXVlKGFtYXpvbiRjb3VudHJ5KQpgYGAKCmBgYHtyfQp1bmlxdWUoYW1hem9uJGxvY2F0aW9uKQpgYGAKCmBgYHtyfQphbWF6b24kY2l0eSA8LSB3b3JkKGFtYXpvbiRsb2NhdGlvbiwgLTEpCnVuaXF1ZShhbWF6b24kY2l0eSkKYGBgCgpMZXQgdXMgY29ycmVjdCB0aGUgY2l0eSBuYW1lcyB0aGF0IGhhdmUgbXVsdGlwbGUgd29yZHMuCmBgYHtyfQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiQWx0byIsIHJlcGxhY2VtZW50ID0gIkVhc3QgUGFsbyBBbHRvIiwgYW1hem9uJGNpdHkpCmFtYXpvbiRjaXR5IDwtIGdzdWIocGF0dGVybiA9ICJJYTxVKzAxNUY+aSIsIHJlcGxhY2VtZW50ID0gIklhc2kiLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gZ3N1YihwYXR0ZXJuID0gIk1vbmljYSIsIHJlcGxhY2VtZW50ID0gIlNhbnRhIE1vbmljYSIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiRnJhbmNpc2NvIiwgcmVwbGFjZW1lbnQgPSAiU2FuIEZyYW5jaXNjbyIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiV3JvY2xhd3NraWUiLCByZXBsYWNlbWVudCA9ICJCaWVsYW55IFdyb2NsYXdza2llIiwgYW1hem9uJGNpdHkpCmFtYXpvbiRjaXR5IDwtIGdzdWIocGF0dGVybiA9ICJEaWVnbyIsIHJlcGxhY2VtZW50ID0gIlNhbiBEaWVnbyIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiQmFyYmFyYSIsIHJlcGxhY2VtZW50ID0gIlNhbnRhIEJhcmJhcmEiLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gZ3N1YihwYXR0ZXJuID0gIllvcmsiLCByZXBsYWNlbWVudCA9ICJOZXcgWW9yayIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiVG93biIsIHJlcGxhY2VtZW50ID0gIkNhcGUgVG93biIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiQ3J1eiIsIHJlcGxhY2VtZW50ID0gIlNhbnRhIENydXoiLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gZ3N1YihwYXR0ZXJuID0gIk9iaXNwbyIsIHJlcGxhY2VtZW50ID0gIlNhbiBMdWlzIE9iaXNwbyIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiUGF1bG8iLCByZXBsYWNlbWVudCA9ICJTYW8gUGF1bG8iLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gZ3N1YihwYXR0ZXJuID0gIkhhc2hhcm9uIiwgcmVwbGFjZW1lbnQgPSAiSG9kIEhhc2hhcm9uIiwgYW1hem9uJGNpdHkpCmFtYXpvbiRjaXR5IDwtIGdzdWIocGF0dGVybiA9ICJJTCwiLCByZXBsYWNlbWVudCA9ICJIb2QgSGFzaGFyb24iLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gZ3N1YihwYXR0ZXJuID0gIk9uLCIsIHJlcGxhY2VtZW50ID0gIk90dGF3YSIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiSm9zZSIsIHJlcGxhY2VtZW50ID0gIlNhbiBKb3NlIiwgYW1hem9uJGNpdHkpCmFtYXpvbiRjaXR5IDwtIGdzdWIocGF0dGVybiA9ICJDQSwiLCByZXBsYWNlbWVudCA9ICJPdHRhd2EiLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gZ3N1YihwYXR0ZXJuID0gIlZlZ2FzIiwgcmVwbGFjZW1lbnQgPSAiTGFzIFZlZ2FzIiwgYW1hem9uJGNpdHkpCmBgYAoKVGhlIHdvcmQgIkNpdHkiIGhhcyBiZWVuIHVzZWQgd2l0aCB0aHJlZSBkaWZmZXJlbnQgY2l0aWVzLCBzbyBpbmNsdWRlIHRoZW0uCgpgYGB7cn0KYW1hem9uJGNpdHkgPC0gaWZlbHNlKGFtYXpvbiRsb2NhdGlvbiA9PSAiVVMsIENBLCBGb3N0ZXIgQ2l0eSIsICJGb3N0ZXIgQ2l0eSIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBpZmVsc2UoYW1hem9uJGxvY2F0aW9uID09ICJNWCwgRU1FWCwgTWV4aWNvIENpdHkiLCAiTWV4aWNvIENpdHkiLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gaWZlbHNlKGFtYXpvbiRsb2NhdGlvbiA9PSAiVVMsIE5KLCBKZXJzZXkgQ2l0eSIsICJKZXJzZXkgQ2l0eSIsIGFtYXpvbiRjaXR5KQpgYGAKCmBgYHtyfQpoZWFkKGFtYXpvbikKYGBgCgojIFdoYXQgYXJlIG1vc3QgcG9wdWxhciBsb2NhdGlvbnMgb2YgSm9iIE9wZW5pbmdzPwoKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxvY2F0aW9uIDwtIGFtYXpvblssIGMoImNvdW50cnkiLCAiY2l0eSIpXQpsb2MxIDwtIGFzLmRhdGEuZnJhbWUodGFibGUobG9jYXRpb24kY2l0eSkpCmNvbG5hbWVzKGxvYzEpIDwtIGMoImNpdHkiLCAiRnJlcSIpCgpsb2MxIDwtIG1lcmdlKGxvYzEsbG9jYXRpb24sYnk9ImNpdHkiKQpsb2MxIDwtIGFycmFuZ2UobG9jMSwgZGVzYyhGcmVxKSkKbG9jMSA8LSBsb2MxICU+JSBkaXN0aW5jdChjaXR5LCAua2VlcF9hbGwgPSBUUlVFKQpsb2MxCmBgYAoKCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTMsIGVjaG89RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShSbWlzYykKdGlsdF90aGVtZSA8LSB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGhlYWQobG9jMSwgMTApLCBhZXMoY2l0eSwgRnJlcSwgZmlsbCA9IGNvdW50cnkpKSArCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9RnJlcSksIGNvbG9yPSJibGFjayIsIHNpemU9MykgKwogICAgICBnZ3RpdGxlKCJUb3AgMTAgSm9iIExvY2F0aW9ucyIpICsgCiAgICAgIGNvb3JkX2ZsaXAoKSArCiAgICAgIHRpbHRfdGhlbWUgCnAxCmBgYAoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9MywgZWNobz1GQUxTRX0KcDIgPC0gZ2dwbG90KGRhdGEgPSB0YWlsKGxvYzEsIDUwKSwgYWVzKGNpdHksIEZyZXEsIGZpbGwgPSBjb3VudHJ5KSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPUZyZXEpLCBjb2xvcj0iYmxhY2siLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiTGFzdCA1MCBKb2IgTG9jYXRpb25zIikgKyAKICAgICAgY29vcmRfZmxpcCgpICsKICAgICAgdGlsdF90aGVtZSAKcDIKYGBgCgpEaXN0cmlidXRpb24gb2YgSm9icyBpbiBhbGwgY291bnRyaWVzIGV4Y2VwdCBVUwpgYGB7cn0KcDMgPC0gZ2dwbG90KGZpbHRlcihsb2MxLGxvYzEkY291bnRyeSE9IlVTIiksIGFlcyh4PWZhY3Rvcihjb3VudHJ5KSwgeT1GcmVxLCBmaWxsID0gZmFjdG9yKGNvdW50cnkpKSkgKyAKICBnZW9tX2JveHBsb3QoKSAKcDMKYGBgCgpEaXN0cmlidXRpb24gb2Ygam9icyBpbiBVUwoKYGBge3J9CnA0IDwtIGdncGxvdChkYXRhID0gZmlsdGVyKGxvYzEsIGxvYzEkY291bnRyeSA9PSAiVVMiKSwgYWVzKGNpdHksIEZyZXEsIGZpbGwgPSBjaXR5KSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPUZyZXEpLCBjb2xvcj0iYmxhY2siLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiSm9icyBpbiBVUyIpICsgCiAgICAgIGNvb3JkX2ZsaXAoKSArCiAgICAgIGd1aWRlcyhmaWxsPUZBTFNFKSArCiAgICAgIHRpbHRfdGhlbWUgCnA0CmBgYAoKIyBBbmFseXNpcyBvZiBKb2IgUG9zdGluZyBEYXRlCgojIyBIb3cgbWFueSBqb2JzIGFyZSBwb3N0ZWQgZXZlcnkgeWVhciBhbmQgZXZlcnkgbW9udGg/IElzIHRoZXJlIGEgY2VydGFpbiBwZXJpb2Qgb2YgeWVhciB3aGVuIGpvYnMgYXJlIHBvc3RlZCBtb3JlIGZlcXVlbnRseT8KCmBgYHtyfQoKYW1hem9uJFBvc3RpbmdfZGF0ZSA8LSBwYXN0ZShhbWF6b24kcG9zdGluZ195ZWFyLCBhbWF6b24kcG9zdGluZ19tb250aCwgYW1hem9uJHBvc3RpbmdfZGF5LHNlcD0iLSIpCgphbWF6b24kUG9zdGluZ19kYXRlIDwtIGFzLkRhdGUoc3RycHRpbWUoYW1hem9uJFBvc3RpbmdfZGF0ZSxmb3JtYXQ9IiVZLSViLSVkIikpCiNhbWF6b24kUG9zdGluZ19kYXRlJHpvbmUgPC0gTlVMTAooYW1hem9uJFBvc3RpbmdfZGF0ZVsxOjEwXSkKCiNnZXQgZGF5IG9mIHRoZSB3ZWVrIGJhc2VkIG9uIGRhdGUKZG93IDwtIGZ1bmN0aW9uKHgpIGZvcm1hdChhcy5EYXRlKHgpLCAiJUEiKQphbWF6b24kd2Vla2RheSA8LSBkb3coYW1hem9uJFBvc3RpbmdfZGF0ZSkKYW1hem9uJHdlZWtkYXlbMToyMF0KYGBgCgpgYGB7cn0KcG9zdGluZ19kYXRlIDwtIGFtYXpvblssYygicG9zdGluZ19tb250aCIsICJwb3N0aW5nX3llYXIiLCAid2Vla2RheSIsICJQb3N0aW5nX2RhdGUiKV0KaGVhZChwb3N0aW5nX2RhdGUpCmBgYAoKYGBge3J9CnllYXIgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShwb3N0aW5nX2RhdGUkcG9zdGluZ195ZWFyKSkKY29sbmFtZXMoeWVhcikgPC0gYygiWWVhciIsICJGcmVxIikKcDUgPC0gZ2dwbG90KGRhdGEgPSB5ZWFyLCBhZXMoWWVhciwgRnJlcSwgZmlsbCA9IFllYXIpKSArCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9RnJlcSksIGNvbG9yPSJibGFjayIsIHNpemU9MykgKwogICAgICBnZ3RpdGxlKCJKb2JzIHBvc3RpbmdzIGJ5IFllYXIiKSArIAogICAgICBndWlkZXMoZmlsbD1GQUxTRSkgKwogICAgICB0aWx0X3RoZW1lIApwNQpgYGAKCmBgYHtyfQptb24gPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShwb3N0aW5nX2RhdGUkcG9zdGluZ19tb250aCkpCmNvbG5hbWVzKG1vbikgPC0gYygiTW9uIiwgIkZyZXEiKQpsZXYgPSBjKCJKYW51YXJ5IiwgIkZlYnJ1YXJ5IiwgIk1hcmNoIiwgIkFwcmlsIiwgIk1heSIsICJKdW5lIiwgIkp1bHkiLCAiQXVndXN0IiwgIlNlcHRlbWJlciIsICJPY3RvYmVyIiwgIk5vdmVtYmVyIiwgIkRlY2VtYmVyIikKbW9uJE1vbnRoIDwtIGZhY3Rvcihtb24kTW9uLCBsZXYpCiAKcDYgPC0gZ2dwbG90KGRhdGEgPSBtb24sIGFlcyhNb250aCwgRnJlcSwgZmlsbCA9IE1vbnRoKSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPUZyZXEpLCBjb2xvcj0iYmxhY2siLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiSm9icyBwb3N0aW5ncyBieSBNb250aCIpICsgCiAgICAgIGd1aWRlcyhmaWxsPUZBTFNFKSArCiAgICAgIHRpbHRfdGhlbWUgCnA2CmBgYAoKYGBge3J9CmpkYXkgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShwb3N0aW5nX2RhdGUkd2Vla2RheSkpCmNvbG5hbWVzKGpkYXkpIDwtIGMoIndkIiwgIkZyZXEiKQpsZXYgPC0gYygiU3VuZGF5IiwgIk1vbmRheSIsICJUdWVzZGF5IiwgIldlZG5lc2RheSIsICJUaHVyc2RheSIsICJGcmlkYXkiLCAiU2F0dXJkYXkiKQpqZGF5JHdlZWtkYXkgPC0gZmFjdG9yKGpkYXkkd2QsIGxldikKCnA3IDwtIGdncGxvdChkYXRhID0gamRheSwgYWVzKHdlZWtkYXksIEZyZXEsIGZpbGwgPSB3ZWVrZGF5KSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPUZyZXEpLCBjb2xvcj0iYmxhY2siLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiSm9icyBwb3N0aW5ncyBieSBXZWVrZGF5IikgKyAKICAgICAgZ3VpZGVzKGZpbGw9RkFMU0UpICsKICAgICAgdGlsdF90aGVtZSAKcDcKYGBgCgpUaGUgYWJvdmUgZ3JhcGhzIHNob3cgdGhhdCBtb3N0IG9mIHRoZSBqb2IgcG9zdGluZ3MgYXJlIHJlY2VudCBhbmQgdGhlcmUgaGFzIGJlZW4gbGFyZ2UgaW5jcmVhc2UgaW4gam9icyBpbiAyMDE3IGFuZCAyMDE4LiBKYW51YXJ5IGFuZCBmZWJydWFyeSBhcmUgaG90IG1vbnRocyBmb3Igam9icy4gQWxzbywgdGhlIGpvYnMgYXJlIHBvc3RlZCBnZW5lcmFsbHkgb24gd2Vla2RheXMsIG1vc3RseSBvbiB0dWVzZGF5cyBhbmQgd2VkbmVzZGF5LiBUaGlzIGlzIHRydWUgYXMgZ2VuZXJhbGx5IGVtcGxveWVlcyBhcmUgY29tcGxldGluZyBtb3JlIHdvcmsgaW4gdGhlIGZpcnN0IGhhbGYgb2Ygd2Vla2RheXMuIAoKIyBBbmFseXNpcyBvZiBKb2IgdGl0bGVzCgojIyBXaGF0IGFyZSBtb3N0IHBvcHVsYXIgam9iIHRpdGxlcz8KCmBgYHtyfQp0aXRsZSA8LSBhcnJhbmdlKGFzLmRhdGEuZnJhbWUodGFibGUoYW1hem9uJFRpdGxlKSksIGRlc2MoRnJlcSkpCmNvbG5hbWVzKHRpdGxlKSA8LSBjKCJUaXRsZSIsICJGcmVxIikKcDggPC0gZ2dwbG90KGRhdGEgPSBoZWFkKHRpdGxlLCAxMCksIGFlcyhUaXRsZSwgRnJlcSwgZmlsbCA9IFRpdGxlKSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPUZyZXEpLCBjb2xvcj0iYmxhY2siLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiVG9wIDEwIGpvYnMiKSArIAogICAgICBndWlkZXMoZmlsbD1GQUxTRSkgKwogICAgICBjb29yZF9mbGlwKCkgKwogICAgICB0aWx0X3RoZW1lIApwOApgYGAKClRoZXJlIGFyZSB2YXJpb3VzIGpvYiBwb3N0aW5ncy4gVG9wIDEwIGFyZSBzaG93biBhYm92ZS4gTGV0IHVzIG5vdyBkaXZpZGUgaXQgaW4gZGlmZmVyZW50IGRvbWFpbnMgYW5kIGRpZmZlcmVudCBwb3NpdGlvbnMuCmBgYHtyfQoKIyBzb2Z0d2FyZSwgZ2FtZSwgcXVhbGl0eSwgZGF0YSwgd2ViLCBzZWN1cml0eSwgc2FsZSxpb3QsIHJlc2VhcmNoCiMgbGVhZCwgbWFuYWdlciwgZGV2ZWxvcGVyLCBlbmdpbmVlciwgY29uc3VsdGFudCwgYXJ0aXN0LCBhbmFseXN0LCBzY2llbnRpc3QsCmRvbWFpbiA8LSBjKCJzb2Z0d2FyZSIsICJnYW1lIiwgInF1YWxpdHkiLCAiZGF0YSIsICJ3ZWIiLCAic2VjdXJpdHkiLCAic2FsZSIsICJyZXNlYXJjaCIsICJpb3QiLCAidWkiKQpwb3NpdGlvbnMgPC0gYygibGVhZCIsICJsZWFkZXIiLCJtYW5hZ2VyIiwgImRldmVsb3BlciIsICJlbmdpbmVlciIsICJjb25zdWx0YW50IiwgImFydGlzdCIsICJhbmFseXN0IiwgInNjaWVudGlzdCIpCmFtYXpvbiRUaXRsZSA8LSB0b2xvd2VyKGFtYXpvbiRUaXRsZSkKI3VuaXF1ZShhbWF6b24kVGl0bGUpCmFtYXpvbiRkb21haW4gPC0gTkEKYW1hem9uJHBvc2l0aW9ucyA8LSBOQQoKYGBgCgoKCmBgYHtyfQpmb3IoaSBpbiBkb21haW4pewphbWF6b24kZG9tYWluMSA8LSBncmVwbChpLCBhbWF6b24kVGl0bGUpCmFtYXpvbiRkb21haW4gPC0gaWZlbHNlKGFtYXpvbiRkb21haW4xID09ICJUUlVFIiwgaSwgYW1hem9uJGRvbWFpbikKfQphbWF6b24kZG9tYWluIDwtIGlmZWxzZShhbWF6b24kZG9tYWluID09IEZBTFNFLCAib3RoZXIiLCBhbWF6b24kZG9tYWluKQoKZm9yKGkgaW4gcG9zaXRpb25zKXsKICBhbWF6b24kcG9zMSA8LSBncmVwbChpLCBhbWF6b24kVGl0bGUpCiAgYW1hem9uJHBvc2l0aW9ucyA8LSBpZmVsc2UoYW1hem9uJHBvczEgPT0gIlRSVUUiLCBpLCBhbWF6b24kcG9zaXRpb25zKQp9CmFtYXpvbiRwb3NpdGlvbnMgPC0gaWZlbHNlKGlzLm5hKGFtYXpvbiRwb3NpdGlvbnMpLCAib3RoZXIiLCBhbWF6b24kcG9zaXRpb25zKQphbWF6b24gPC0gc3Vic2V0KGFtYXpvbiwgc2VsZWN0ID0gLWMoZG9tYWluMSwgcG9zMSkpCgpgYGAKCmBgYHtyfQpwb3MgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShhbWF6b24kcG9zaXRpb25zKSkKY29sbmFtZXMocG9zKSA8LSBjKCJwb3NpdGlvbiIsICJGcmVxIikKcDkgPC0gZ2dwbG90KGRhdGEgPSBwb3MsIGFlcyhwb3NpdGlvbiwgRnJlcSwgZmlsbCA9IHBvc2l0aW9uKSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPUZyZXEpLCBjb2xvcj0iYmxhY2siLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiVG9wIDEwIGRvbWFpbnMiKSArIAogICAgICBndWlkZXMoZmlsbD1GQUxTRSkgKwogICAgICBjb29yZF9mbGlwKCkgCnA5CmBgYAoKYGBge3J9CmRvbSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGFtYXpvbiRkb21haW4pKQpjb2xuYW1lcyhkb20pIDwtIGMoImRvbWFpbiIsICJGcmVxIikKcDkgPC0gZ2dwbG90KGRhdGEgPSBkb20sIGFlcyhkb21haW4sIEZyZXEsIGZpbGwgPSBkb21haW4pKSArCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9RnJlcSksIGNvbG9yPSJibGFjayIsIHNpemU9MykgKwogICAgICBnZ3RpdGxlKCJUb3AgMTAgZG9tYWlucyIpICsgCiAgICAgIGd1aWRlcyhmaWxsPUZBTFNFKSArCiAgICAgIGNvb3JkX2ZsaXAoKSAKcDkKYGBgCgojIFdoYXQgYXJlIG1pbmltdW0gZWR1Y2F0aW9uYWwgcXVhbGlmaWNhdGlvbnM/CgpgYGB7cn0KYW1hem9uJGVkdWNhdGlvbiA8LSBOQQpkZWdyZWVfbGlzdCA9IGMoImJhIiwgImJzIiwgImIudGVjaCIsImJhY2hlbG9yIiwgInBoZCIsIm1zIiwibWFzdGVyIiwgIm1iYSIsIm0udGVjaCIpCmFtYXpvbiRgQkFTSUMgUVVBTElGSUNBVElPTlNgIDwtIHRvbG93ZXIoYW1hem9uJGBCQVNJQyBRVUFMSUZJQ0FUSU9OU2ApCgpmb3IoaSBpbiBkZWdyZWVfbGlzdCl7CiAgYW1hem9uJGRlZzEgPC0gZ3JlcGwoaSwgYW1hem9uJGBCQVNJQyBRVUFMSUZJQ0FUSU9OU2ApCiAgYW1hem9uJGVkdWNhdGlvbiA8LSBpZmVsc2UoYW1hem9uJGRlZzEgPT0gIlRSVUUiLCBpLCBhbWF6b24kZWR1Y2F0aW9uKQp9CmFtYXpvbiRlZHVjYXRpb24gPC0gaWZlbHNlKGlzLm5hKGFtYXpvbiRlZHVjYXRpb24pLCAib3RoZXIiLCBhbWF6b24kZWR1Y2F0aW9uKQphbWF6b24gPC0gc3Vic2V0KGFtYXpvbiwgc2VsZWN0ID0gLWMoZGVnMSkpCgpgYGAKCmBgYHtyfQplZHUgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShhbWF6b24kZWR1Y2F0aW9uKSkKY29sbmFtZXMoZWR1KSA8LSBjKCJFZHVjYXRpb24iLCAiRnJlcSIpCnAxMCA8LSBnZ3Bsb3QoZGF0YSA9IGVkdSwgYWVzKEVkdWNhdGlvbiwgRnJlcSwgZmlsbCA9IEVkdWNhdGlvbikpICsKICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1GcmVxKSwgY29sb3I9ImJsYWNrIiwgc2l6ZT0zKSArCiAgICAgIGdndGl0bGUoIkpvYnMgYmFzZWQgb24gZGVncmVlcyIpICsgCiAgICAgIGd1aWRlcyhmaWxsPUZBTFNFKSArCiAgICAgIGNvb3JkX2ZsaXAoKSAKcDEwCmBgYAoKQmFzaWMgUXVhbGlmaWNhdGlvbnMgZ2VuZXJhbGx5IHJlcXVpcmVzIE1hc3RlcnMgZGVncmVlLgoKIyMgV2hpY2ggam9icyByZXF1aXJlIHdoaWNoIHR5cGUgb2YgZGVncmVlcz8KCgpgYGB7ciBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBlY2hvPUZBTFNFfQpjb3VudHMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShhbWF6b24kZG9tYWluLCBhbWF6b24kZWR1Y2F0aW9uKSkKY29sbmFtZXMoY291bnRzKSA8LSBjKCJEb21haW4iLCAiRWR1Y2F0aW9uIiwgIkZyZXEiKQpwMTEgPC0gZ2dwbG90KGRhdGEgPSBmaWx0ZXIoY291bnRzLCBjb3VudHMkRG9tYWluICE9ICJzb2Z0d2FyZSIpLCBhZXMoRG9tYWluLCBGcmVxKSkgKwogICAgICBnZW9tX2JhcihhZXMoZmlsbCA9IEVkdWNhdGlvbiksIHBvc2l0aW9uID0gImRvZGdlIixzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZ3RpdGxlKCJEb21haW4gZGlzdHJpYnV0aW9uIGJhc2VkIG9uIEVkdWNhdGlvbiIpIAoKcDEyIDwtIGdncGxvdChkYXRhID0gZmlsdGVyKGNvdW50cywgY291bnRzJERvbWFpbiA9PSAic29mdHdhcmUiKSwgYWVzKERvbWFpbiwgRnJlcSkpICsKICAgICAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBFZHVjYXRpb24pLCBwb3NpdGlvbiA9ICJkb2RnZSIsc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2d0aXRsZSgiRG9tYWluIGRpc3RyaWJ1dGlvbiBiYXNlZCBvbiBFZHVjYXRpb24iKSAKbXVsdGlwbG90KHAxMSwgcDEyKQpgYGAKCmBgYHtyIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsIGVjaG89RkFMU0V9CmNvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGFtYXpvbiRwb3NpdGlvbnMsIGFtYXpvbiRlZHVjYXRpb24pKQpjb2xuYW1lcyhjb3VudHMpIDwtIGMoIlBvc2l0aW9ucyIsICJFZHVjYXRpb24iLCAiRnJlcSIpCnAxMyA8LSBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihjb3VudHMsIGNvdW50cyRQb3NpdGlvbnMgIT0gImVuZ2luZWVyIiksIGFlcyhQb3NpdGlvbnMsIEZyZXEpKSArCiAgICAgIGdlb21fYmFyKGFlcyhmaWxsID0gRWR1Y2F0aW9uKSwgcG9zaXRpb24gPSAiZG9kZ2UiLHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdndGl0bGUoIlBvc2l0aW9ucyBkaXN0cmlidXRpb24gYmFzZWQgb24gRWR1Y2F0aW9uIikgCgpwMTQgPC0gZ2dwbG90KGRhdGEgPSBmaWx0ZXIoY291bnRzLCBjb3VudHMkUG9zaXRpb25zID09ICJlbmdpbmVlciIpLCBhZXMoUG9zaXRpb25zLCBGcmVxKSkgKwogICAgICBnZW9tX2JhcihhZXMoZmlsbCA9IEVkdWNhdGlvbiksIHBvc2l0aW9uID0gImRvZGdlIixzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZ3RpdGxlKCJQb3NpdGlvbnMgZGlzdHJpYnV0aW9uIGJhc2VkIG9uIEVkdWNhdGlvbiIpIAptdWx0aXBsb3QocDEzLCBwMTQpCmBgYAoKIyBXaGF0IGxhbmd1YWdlcyBhcmUgaW4gZGVtYW5kPwoKYGBge3J9Cmxpc3Rfb2Zfb2NjdXJlbmNlIDwtIGMoKQpsYW5ndWFnZXMgPC0gYygnc3dpZnQnLCdtYXRsYWInLCdtb25nb2RiJywnaGFkb29wJywnY29zbW9zJywgJ215c3FsJywnc3BhcmsnLCAncGlnJywgJ3B5dGhvbicsICdqYXZhLicsICdqYXZhLCcsJ2NbKytdJywgJ3BocCcsICdqYXZhc2NyaXB0JywgJ29iamVjdGl2ZSBjJywgJ3J1YnknLCAncGVybCcsJ2MgJywnYyMnLCAnIHIsJykKYW1hem9uJGBQUkVGRVJSRUQgUVVBTElGSUNBVElPTlNgIDwtIHRvbG93ZXIoYW1hem9uJGBQUkVGRVJSRUQgUVVBTElGSUNBVElPTlNgKQoKZm9yKGkgaW4gbGFuZ3VhZ2VzKXsKICBhbWF6b24kZHVtbXkgPC0gc3RyX2NvdW50KGFtYXpvbiRgUFJFRkVSUkVEIFFVQUxJRklDQVRJT05TYCwgaSkKICBsaXN0X29mX29jY3VyZW5jZSA8LSBjKGxpc3Rfb2Zfb2NjdXJlbmNlLCBzdW0oYW1hem9uJGR1bW15LCBuYS5ybSA9IFRSVUUpKQp9Cmxpc3Rfb2Zfb2NjdXJlbmNlCmBgYAoKYGBge3J9CmxhbiA8LSBkYXRhLmZyYW1lKGNiaW5kKGxhbmd1YWdlcywgYXMubnVtZXJpYyhsaXN0X29mX29jY3VyZW5jZSkpKQpwMTUgPC0gZ2dwbG90KGRhdGEgPSBsYW4sIGFlcyhsYW5ndWFnZXMsIGxpc3Rfb2Zfb2NjdXJlbmNlLCBmaWxsID0gbGFuZ3VhZ2VzKSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPWxpc3Rfb2Zfb2NjdXJlbmNlKSwgY29sb3I9ImJsYWNrIiwgc2l6ZT0zKSArCiAgICAgIGdndGl0bGUoIkxhbmd1YWdlcyBpbiBqb2IgZGVzY3JpcHRpb24iKSArIAogICAgICBndWlkZXMoZmlsbD1GQUxTRSkgKwogICAgICBjb29yZF9mbGlwKCkgCnAxNQpgYGAKCkphdmEsIEMsIEMrKyBhbmQgcHl0aG9uIGFyZSBwb3B1bGFyIG9uLWRlbWFuZCBsYW5ndWFnZXMgaW4gam9icy4KCgojIEhvdyBtYW55IHllYXJzIG9mIGV4cGVyaWVuY2UgaXMgcmVxdWlyZWQ/CgpgYGB7cn0KYW1hem9uJGR1bW15IDwtIHN0cl9leHRyYWN0KGFtYXpvbiRgQkFTSUMgUVVBTElGSUNBVElPTlNgLCAnKFswLTldKykgeWVhcicpCmFtYXpvbiRkdW1teSA8LSBpZmVsc2UoaXMubmEoYW1hem9uJGR1bW15KSwgIjAgeWVhciIsIGFtYXpvbiRkdW1teSkKCnNwbGl0X3llYXIgPC0gZnVuY3Rpb24odmFyKXsKIHJldHVybihhcy5udW1lcmljKHVubGlzdChzdHJfc3BsaXQodmFyLCAiICIpKVsxXSkpCn0KYW1hem9uJGV4cGVyaWVuY2UgPC0gc2FwcGx5KGFtYXpvbiRkdW1teSwgc3BsaXRfeWVhcikKCmBgYAoKTGV0J3Mgc2VlIHRoZSBleHBlcmllbmNlLCBleGNsdWRpbmcgMCB5ZWFyIGV4cGVyaWVuY2UuCmBgYHtyfQpleHAgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShhbWF6b24kZXhwZXJpZW5jZSkpCmNvbG5hbWVzKGV4cCkgPC0gYygiRXhwZXJpZW5jZSIsICJGcmVxIikKcDE2IDwtIGdncGxvdChkYXRhID0gZmlsdGVyKGV4cCwgZXhwJEV4cGVyaWVuY2UgIT0gMCksIGFlcyhFeHBlcmllbmNlLCBGcmVxLCBmaWxsID0gRXhwZXJpZW5jZSkpICsKICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1GcmVxKSwgY29sb3I9ImJsYWNrIiwgc2l6ZT0zKSArCiAgICAgIGdndGl0bGUoIkV4cGVyaWVuY2UgbmVlZGVkIikgKyAKICAgICAgZ3VpZGVzKGZpbGw9RkFMU0UpICsKICAgICAgY29vcmRfZmxpcCgpIApwMTYKYGBgCgpgYGB7ciBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBlY2hvPUZBTFNFfQpjb3VudHMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShhbWF6b24kcG9zaXRpb25zLCBhbWF6b24kZXhwZXJpZW5jZSkpCmNvbG5hbWVzKGNvdW50cykgPC0gYygiUG9zaXRpb25zIiwgIkV4cGVyaWVuY2UiLCAiRnJlcSIpCnAxNyA8LSBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihjb3VudHMsIGNvdW50cyRFeHBlcmllbmNlICE9IDAgJiBjb3VudHMkUG9zaXRpb25zICE9ICJlbmdpbmVlciIpLCBhZXMoUG9zaXRpb25zLCBGcmVxKSkgKwogICAgICBnZW9tX2JhcihhZXMoZmlsbCA9IEV4cGVyaWVuY2UpLCBwb3NpdGlvbiA9ICJkb2RnZSIsc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2d0aXRsZSgiUG9zaXRpb25zIGRpc3RyaWJ1dGlvbiBiYXNlZCBvbiBFeHBlcmllbmNlIGZvciBwb3NpdGlvbnMgZXhjbHVkaW5nIGVuZ2lubmVyIikgCnAxOCA8LSBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihjb3VudHMsIGNvdW50cyRFeHBlcmllbmNlID09IDAgJiBjb3VudHMkUG9zaXRpb25zICE9ICJlbmdpbmVlciIpLCBhZXMoUG9zaXRpb25zLCBGcmVxKSkgKwogICAgICBnZW9tX2JhcihhZXMoZmlsbCA9IEV4cGVyaWVuY2UpLCBwb3NpdGlvbiA9ICJkb2RnZSIsc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2d0aXRsZSgiUG9zaXRpb25zIHdoZXJlIEV4cGVyaWVuY2UgaXMgbm90IGRlZmluZWQgZXhjbHVkaW5nIGVuZ2luZWVyIikgCnAxOSA8LSBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihjb3VudHMsIGNvdW50cyRQb3NpdGlvbnMgPT0gImVuZ2luZWVyIiksIGFlcyhQb3NpdGlvbnMsIEZyZXEpKSArCiAgICAgIGdlb21fYmFyKGFlcyhmaWxsID0gRXhwZXJpZW5jZSksIHBvc2l0aW9uID0gImRvZGdlIixzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZ3RpdGxlKCJFbmdpbmVlciBQb3NpdGlvbnMgZGlzdHJpYnV0aW9uIGJhc2VkIG9uIEV4cGVyaWVuY2UiKSAKcDIwIDwtIGdncGxvdChkYXRhID0gZmlsdGVyKGNvdW50cywgY291bnRzJEV4cGVyaWVuY2UgIT0gMCAmIGNvdW50cyRQb3NpdGlvbnMgPT0gImVuZ2luZWVyIiksIGFlcyhQb3NpdGlvbnMsIEZyZXEpKSArCiAgICAgIGdlb21fYmFyKGFlcyhmaWxsID0gRXhwZXJpZW5jZSksIHBvc2l0aW9uID0gImRvZGdlIixzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZ3RpdGxlKCJFbmdpbmVlciBQb3NpdGlvbnMgd2hlcmUgRXhwZXJpZW5jZSBpcyBub3QgemVybyIpIAptdWx0aXBsb3QocDE3LCBwMTgsIHAxOSwgcDIwLCBsYXlvdXQgPSBtYXRyaXgoYygxLDIsMyw0KSwgbnJvdz0yLCBieXJvdz1UUlVFKSkKCmBgYAoKYGBge3IgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZWNobz1GQUxTRX0KY291bnRzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoYW1hem9uJGRvbWFpbiwgYW1hem9uJGV4cGVyaWVuY2UpKQpjb2xuYW1lcyhjb3VudHMpIDwtIGMoIkRvbWFpbiIsICJFeHBlcmllbmNlIiwgIkZyZXEiKQpwMjEgPC0gZ2dwbG90KGRhdGEgPSBmaWx0ZXIoY291bnRzLCBjb3VudHMkRXhwZXJpZW5jZSAhPSAwICYgY291bnRzJERvbWFpbiAhPSAic29mdHdhcmUiKSwgYWVzKERvbWFpbiwgRnJlcSkpICsKICAgICAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBFeHBlcmllbmNlKSwgcG9zaXRpb24gPSAiZG9kZ2UiLHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdndGl0bGUoIkRvbWFpbiBkaXN0cmlidXRpb24gYmFzZWQgb24gRXhwZXJpZW5jZSBmb3IgZG9tYWluIGV4Y2x1ZGluZyBzb2Z0d2FyZSIpIAoKcDIyIDwtIGdncGxvdChkYXRhID0gZmlsdGVyKGNvdW50cywgY291bnRzJEV4cGVyaWVuY2UgPT0gMCAmIGNvdW50cyREb21haW4gIT0gInNvZnR3YXJlIiksIGFlcyhEb21haW4sIEZyZXEpKSArCiAgICAgIGdlb21fYmFyKGFlcyhmaWxsID0gRXhwZXJpZW5jZSksIHBvc2l0aW9uID0gImRvZGdlIixzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZ3RpdGxlKCJEb21haW4gd2hlcmUgRXhwZXJpZW5jZSBpcyBub3QgZGVmaW5lZCBmb3IgZG9tYWluIGV4Y2x1ZGluZyBzb2Z0d2FyZSIpIAoKcDIzIDwtIGdncGxvdChkYXRhID0gZmlsdGVyKGNvdW50cywgY291bnRzJERvbWFpbiA9PSAic29mdHdhcmUiKSwgYWVzKERvbWFpbiwgRnJlcSkpICsKICAgICAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBFeHBlcmllbmNlKSwgcG9zaXRpb24gPSAiZG9kZ2UiLHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdndGl0bGUoIkRvbWFpbiBkaXN0cmlidXRpb24gYmFzZWQgb24gRXhwZXJpZW5jZSBmb3Igc29mdHdhcmUiKSAKCnAyNCA8LSBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihjb3VudHMsIGNvdW50cyRFeHBlcmllbmNlICE9IDAgJiBjb3VudHMkRG9tYWluID09ICJzb2Z0d2FyZSIpLCBhZXMoRG9tYWluLCBGcmVxKSkgKwogICAgICBnZW9tX2JhcihhZXMoZmlsbCA9IEV4cGVyaWVuY2UpLCBwb3NpdGlvbiA9ICJkb2RnZSIsc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2d0aXRsZSgiRG9tYWluIHdoZXJlIEV4cGVyaWVuY2UgaXMgbm90IHplcm8gZm9yIHNvZnR3YXJlIikgCgptdWx0aXBsb3QocDIxLCBwMjIsIHAyMywgcDI0LCBsYXlvdXQgPSBtYXRyaXgoYygxLDIsMyw0KSwgbnJvdz0yLCBieXJvdz1UUlVFKSkKYGBgCgojIFdvcmQgQ2xvdWRzIG9mIFF1YWxpZmljYXRpb25zIGFuZCBKb2IgZGVzY3JpcHRpb24KCmBgYHtyfQpsaWJyYXJ5KHdvcmRjbG91ZCkKbGlicmFyeShTbm93YmFsbEMpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHRtKQp0ZXh0cyA8LSBhbWF6b24kYFBSRUZFUlJFRCBRVUFMSUZJQ0FUSU9OU2AKI3RleHRzIDwtIGljb252KHRleHRzLCB0byA9ICJ1dGYtOCIpCmNvcnB1cyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKHRleHRzKSkKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIFBsYWluVGV4dERvY3VtZW50KQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlUHVuY3R1YXRpb24pCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVXb3Jkcywgc3RvcHdvcmRzKCdlbmdsaXNoJykpCiNjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgc3RlbURvY3VtZW50KQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlV29yZHMsIGMoIjAwYjciLCJhbmQiLCAidGhpcyIsICJ0aGVyZSIpKSAKY29ycHVzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UoY29ycHVzKSkKZHRtIDwtIFRlcm1Eb2N1bWVudE1hdHJpeChjb3JwdXMpCm0gPC0gYXMubWF0cml4KGR0bSkKdiA8LSBzb3J0KHJvd1N1bXMobSksZGVjcmVhc2luZz1UUlVFKQpkIDwtIGRhdGEuZnJhbWUod29yZCA9IG5hbWVzKHYpLGZyZXE9dikKaGVhZChkLCAxMCkKZCA8LSBkWy13aGljaChkJHdvcmQgJWluJSBjKCIwMGI3IiwiYW5kIiwidGhpcyIsInRoYXQiKSksXQpzZXQuc2VlZCgxMjM0KQp3b3JkY2xvdWQod29yZHMgPSBkJHdvcmQsIGZyZXEgPSBkJGZyZXEsIG1pbi5mcmVxID0gMSwKICAgICAgICAgIG1heC53b3Jkcz0yMDAsIHJhbmRvbS5vcmRlcj1GQUxTRSwgcm90LnBlcj0wLjM1LCAKICAgICAgICAgIGNvbG9ycz1icmV3ZXIucGFsKDgsICJEYXJrMiIpKQp0aXRsZSgiUHJlZmVycmVkIFF1YWxpZmljYXRpb25zIFdvcmQgQ2xvdWQiKQpgYGAKCmBgYHtyfQp0ZXh0cyA8LSBhbWF6b24kYEJBU0lDIFFVQUxJRklDQVRJT05TYAojdGV4dHMgPC0gaWNvbnYodGV4dHMsIHRvID0gInV0Zi04IikKY29ycHVzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UodGV4dHMpKQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgUGxhaW5UZXh0RG9jdW1lbnQpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVQdW5jdHVhdGlvbikKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoJ2VuZ2xpc2gnKSkKI2NvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBzdGVtRG9jdW1lbnQpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVXb3JkcywgYygiMDBiNyIsImFuZCIsICJ0aGlzIiwgInRoZXJlIikpIApjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZShjb3JwdXMpKQpkdG0gPC0gVGVybURvY3VtZW50TWF0cml4KGNvcnB1cykKbSA8LSBhcy5tYXRyaXgoZHRtKQp2IDwtIHNvcnQocm93U3VtcyhtKSxkZWNyZWFzaW5nPVRSVUUpCmQgPC0gZGF0YS5mcmFtZSh3b3JkID0gbmFtZXModiksZnJlcT12KQpoZWFkKGQsIDEwKQpkIDwtIGRbLXdoaWNoKGQkd29yZCAlaW4lIGMoIjAwYjciLCJhbmQiLCJ0aGlzIiwidGhhdCIpKSxdCnNldC5zZWVkKDEyMzQpCndvcmRjbG91ZCh3b3JkcyA9IGQkd29yZCwgZnJlcSA9IGQkZnJlcSwgbWluLmZyZXEgPSAxLAogICAgICAgICAgbWF4LndvcmRzPTIwMCwgcmFuZG9tLm9yZGVyPUZBTFNFLCByb3QucGVyPTAuMzUsIAogICAgICAgICAgY29sb3JzPWJyZXdlci5wYWwoOCwgIkRhcmsyIikpCnRpdGxlKCJCYXNpYyBRdWFsaWZpY2F0aW9ucyBXb3JkIENsb3VkIikKYGBgCgpgYGB7ciAgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NSwgZWNobz1GQUxTRX0KdGV4dHMgPC0gYW1hem9uJERFU0NSSVBUSU9OCiN0ZXh0cyA8LSBpY29udih0ZXh0cywgdG8gPSAidXRmLTgiKQpjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0cykpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBQbGFpblRleHREb2N1bWVudCkKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVB1bmN0dWF0aW9uKQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygnZW5nbGlzaCcpKQojY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHN0ZW1Eb2N1bWVudCkKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVdvcmRzLCBjKCIwMGI3IiwiYW5kIiwgInRoaXMiLCAidGhlcmUiLCAieW91IiwgIndpbGwiKSkgCmNvcnB1cyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKGNvcnB1cykpCmR0bSA8LSBUZXJtRG9jdW1lbnRNYXRyaXgoY29ycHVzKQptIDwtIGFzLm1hdHJpeChkdG0pCnYgPC0gc29ydChyb3dTdW1zKG0pLGRlY3JlYXNpbmc9VFJVRSkKZCA8LSBkYXRhLmZyYW1lKHdvcmQgPSBuYW1lcyh2KSxmcmVxPXYpCmhlYWQoZCwgMTApCmQgPC0gZFstd2hpY2goZCR3b3JkICVpbiUgYygiMDBiNyIsImFuZCIsInRoaXMiLCJ0aGF0IiwgInlvdSIsICJ3aWxsIikpLF0Kc2V0LnNlZWQoMTIzNCkKd29yZGNsb3VkKHdvcmRzID0gZCR3b3JkLCBmcmVxID0gZCRmcmVxLCBtaW4uZnJlcSA9IDEsCiAgICAgICAgICBtYXgud29yZHM9MjAwLCByYW5kb20ub3JkZXI9RkFMU0UsIHJvdC5wZXI9MC4zNSwgCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg4LCAiRGFyazIiKSkKdGl0bGUoIkpvYiBEZXNjcmlwdGlvbiBXb3JkIENsb3VkIikKYGBgCgpgYGB7cn0KdGV4dHMgPC0gYW1hem9uJFRpdGxlCiN0ZXh0cyA8LSBpY29udih0ZXh0cywgdG8gPSAidXRmLTgiKQpjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0cykpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBQbGFpblRleHREb2N1bWVudCkKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVB1bmN0dWF0aW9uKQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygnZW5nbGlzaCcpKQojY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHN0ZW1Eb2N1bWVudCkKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVdvcmRzLCBjKCIwMGI3IiwiYW5kIiwgInRoaXMiLCAidGhlcmUiLCAieW91IiwgIndpbGwiKSkgCmNvcnB1cyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKGNvcnB1cykpCmR0bSA8LSBUZXJtRG9jdW1lbnRNYXRyaXgoY29ycHVzKQptIDwtIGFzLm1hdHJpeChkdG0pCnYgPC0gc29ydChyb3dTdW1zKG0pLGRlY3JlYXNpbmc9VFJVRSkKZCA8LSBkYXRhLmZyYW1lKHdvcmQgPSBuYW1lcyh2KSxmcmVxPXYpCmhlYWQoZCwgMTApCiNkIDwtIGRbLXdoaWNoKGQkd29yZCAlaW4lIGMoIjAwYjciLCJhbmQiLCJ0aGlzIiwidGhhdCIsICJ5b3UiLCAid2lsbCIpKSxdCnNldC5zZWVkKDEyMzQpCndvcmRjbG91ZCh3b3JkcyA9IGQkd29yZCwgZnJlcSA9IGQkZnJlcSwgbWluLmZyZXEgPSAxLAogICAgICAgICAgbWF4LndvcmRzPTIwMCwgcmFuZG9tLm9yZGVyPUZBTFNFLCByb3QucGVyPTAuMzUsIAogICAgICAgICAgY29sb3JzPWJyZXdlci5wYWwoOCwgIkRhcmsyIikpCnRpdGxlKCJKb2IgVGl0bGUgV29yZCBDbG91ZCIpCmBgYAoKCg==